#include "esp8266.h"

uint8_t init_success_flag = 0;  // esp8266初始化成功标志位
uint8_t create_server_flag = 0; // esp8266创建服务器标志位
uint8_t passthrough_mode = 0;   // 透传模式标志位
// Elc_Info elc1; // 端口1
// Elc_Info elc2; // 端口2
// Elc_Info elc3; // 端口3

Elc_Info elc1;  // 端口1
Elc_Info elc2;  // 端口2
Elc_Info elc3;  // 端口3
Other_Info oth; // 其他信息

/**
 * @brief  向esp8266发送命令
 * @param  cmd  		发送的命令字符串
 * @param  ack  		期待的应答结果，如果为空，则表示不需要等待应答
 * @param  waittime 	等待时间(单位:10ms)
 * @retval 返回0 表示成功   返回1 表示失败
 */
uint8_t esp8266_send_cmd(char *cmd, uint8_t *ack, uint16_t waittime)
{
    uint8_t res = 0;
    CLR_Buf1();
    u1_printf("%s\r\n", cmd); // 发送指定的命令
    // printf("%s\r\n", cmd); // 发送指定的命令
    if (ack && waittime) // 等待超时时间或者接收指令为空
    {
        while (--waittime) // 等待倒计时
        {
            // HAL_Delay(10);            // 延时10ms

            // OSTimeDlyHMSM(0, 0, 0, 10, OS_OPT_TIME_HMSM_STRICT, &err);
            for (size_t i = 0; i < 0XFFFFF; i++)
            {
                /* code */
            }

            if (receive_success_flag) // 等待接收成功应答标志位，等待中断里响应成功的标志位
            {
                if (esp8266_check_cmd(ack)) // 判断是否接收到对应的指令
                {
                    // printf("esp8266_ack: %s\r\n", (uint8_t *)ack);
                    CLR_Buf1();
                    break; // 得到有效数据
                }
                CLR_Buf1();
                // receive_success_flag = 0;  // 清空接收成功标志位
            }
        }
        if (waittime == 0) // 时间超出
            res = 1;
    }
    return res;
}

/**
 * @brief  向esp8266发送命令后，检测接收到的应答
 * @param  str  期待的应答结果
 * @retval 返回应答的应答的结果，如果没有返回空指针
 */
uint8_t *esp8266_check_cmd(uint8_t *str)
{
    char *strx = NULL;
    strx = strstr((const char *)USART1_RX_BUF, (const char *)str);
    // return (uint8_t *)strx;
    if (strx)
    {
        return str;
    }
    else
        return NULL;
}

/**
 * @brief  向esp8266发送数据
 * @param  data  		发送的数据字符串
 * @param  waittime	等待的时间
 * @retval 返回应答的结果，如果没有返回空指针
 */
uint8_t *esp8266_send_data(uint8_t *data, uint16_t waittime)
{
    char temp[5];
    char *ack = temp;
    CLR_Buf1();
    u1_printf("%s", data); // 发送命令
    if (waittime)
    {
        while (--waittime)
        {
            for (size_t i = 0; i < 0XFFFFFF; i++)
            {
                /* code */
            }
            if (receive_success_flag) // 接收到期待的应答结果, 等待响应成功
            {
                ack = (char *)USART1_RX_BUF; // 接收应答
                printf("esp8266_ack:  %s\r\n", (uint8_t *)ack);
                CLR_Buf1();
                break;
            }
        }
    }
    return (uint8_t *)ack;
}

/**
 * @brief 重启模块
 *
 */
void esp8266_Rst(void)
{
    u1_printf("AT+RST\r\n");
    // HAL_Delay(1000);
    // HAL_Delay(1000);
    // HAL_Delay(1000);
    for (size_t i = 0; i < 0XFFFFFF; i++)
    {
        /* code */
    }

    CLR_Buf1();
}

/**
 * @brief 设置esp8266工作模式
 * @param mode  1 表示 STA模式
 *              2 表示 AP模式
 *              3 表示 STA和AP模式
 * @retval 0 表示成功  1 表示 失败
 */
uint8_t esp8266_set_mode(uint8_t mode)
{
    char temp_buf[50] = {0};
    sprintf(temp_buf, "AT+CWMODE=%d", mode);
    uint8_t isSuccessFlag = esp8266_send_cmd(temp_buf, "OK", 50);
    return isSuccessFlag;
}

/**
 * @brief esp8266连接手机wifi
 *
 * @param name  手机热点名称
 * @param password 手机人点密码
 * @return uint8_t 0表示成功  1 表示失败
 */
uint8_t esp8266_connect_wifi(char *name, char *password)
{
    char temp_buf[50];
    sprintf(temp_buf, "AT+CWJAP=\"%s\",\"%s\"", name, password);
    uint8_t isSuccessFlag = esp8266_send_cmd(temp_buf, "OK", 1000);
    return isSuccessFlag;
}

///**
// * @brief esp8266设置自己wifi的名字，密码
// *
// * @param name wifi名称
// * @param password wifi密码
// * @param Channel wifi通道
// * @param Ecn  加密方式 (0 - OPEN, 1 - WEP, 2 - WPA_PSK, 3 - WPA2_PSK, 4 - WPA_WPA2_PSK)
// * @return uint8_t 0表示成功  1  表示失败
// */
// uint8_t esp8266_set_wifi(char *name, char *password, int Channel, int Ecn)
//{
//    char temp_buf[50];
//    sprintf(temp_buf, "AT+CWSAP=\"%s\",\"%s\",%d,%d",name, password, Channel, Ecn);
//    uint8_t isSuccessFlag = esp8266_send_cmd(temp_buf, "OK", 50);
//    return isSuccessFlag;
//}

/**
 * @brief esp8266连接服务器
 *
 * @param ip 服务器的IP地址
 * @param com 服务器的端口号
 * @return uint8_t 0 表示成功  1 表示失败
 */
uint8_t esp8266_connect_server(char *ip, int com)
{
    char temp_buf[50];
    sprintf(temp_buf, "AT+CIPSTART=\"TCP\",\"%s\",%d", ip, com);
    uint8_t isSuccessFlag = esp8266_send_cmd(temp_buf, "OK", 50);
    return isSuccessFlag;
}

/**
 * @brief esp8266通过服务器——发送指令给服务器
 *
 * @param content 发送的内容
 */
void esp8266_send_server(char *content)
{
    uint32_t len = strlen(content); // 长度
    u1_printf("AT+CIPSEND=%d\r\n", len);
    // 不能在中断函数中调用下列函数，否则会造成程序卡死,Hal_Delay()不能在中断函数中调用，会造成程序卡死
    // esp8266_send_cmd(temp_buf, "OK", 50);  // 发送指令
    // esp8266_send_data(content, 50);  // 发送信息给服务器
    for (int i = 0XFFFF; i > 0; i--)
        ;
    u1_printf(content);
}

/**
 * @brief esp8266等待重新连接上手机热点,并重新连接服务器
 *
 */
void esp8266_reconnect_wifi(void)
{
    CLR_Buf1(); // 清空接受区
    // transmit_mode = 0; // 无模式
    //  HAL_TIM_Base_Stop_IT(&htim3); // 关闭定时器3
    printf("esp8266已断开手机连接\r\n正在尝试重新连接...\r\n");
    while (esp8266_connect_wifi(SSID, PASS))
        ;
    // while (!strstr((const char *)USART1_RX_BUF, "WIFI GOT IP"))
    //     ; // 等待重新连接上wifi
    printf("esp8266重新连接成功\r\n");

    printf("正在重新连接服务器\r\n");
    while (esp8266_connect_server(IPBUF, PORTNUM))  // 等待连接成功，如果不成功将会一直等待
    {
        printf("连接失败,请检查连接的是否为同一个地址\r\n");
    }
    printf("服务器连接成功\r\n");
    // transmit_mode = 1; // 发送信息给服务器
    // disconnct_flag = 0; // 标志位清零
    // HAL_TIM_Base_Start_IT(&htim3); // 开启定时器3更新中断，1s进入一次中断
}

/**
 * @brief esp8266等待重新连接上服务器
 *
 */
void esp8266_reconnect_server(void)
{
    CLR_Buf1(); // 清除接收缓冲区
    // transmit_mode = 0;
    // HAL_TIM_Base_Stop_IT(&htim3); // 关闭定时器3
    printf("已断开服务器连接, 请检查服务器是否断开\r\n");
    printf("正在重新尝试连接服务器....\r\n");
    while (esp8266_connect_server(IPBUF, PORTNUM))
        ; // 等待服务器连接成功
    printf("服务器重新连接成功\r\n");
    // transmit_mode = 1;
    // disconnct_flag = 0; // 标志位清零
    // HAL_TIM_Base_Start_IT(&htim3); // 开启定时器3更新中断,1s 进入一次中断
}

/**
 * @brief esp8266连接时间网站IP，获取当前时间
 *
 * @return uint8_t  0 表示成功   1 表示失败
 */
uint8_t esp8266_connect_ntim(void)
{
    uint8_t isSuccessFlag = esp8266_connect_server(TIMIP, TIMPORT); // 连接时间网站服务器
    if (isSuccessFlag == 0)
    {
        printf("连接%s成功\r\n", TIMIP);
        return 0;
    }
    else
    {
        printf("连接失败, 正在尝试重新连接\r\n");
        return 1;
    }
}

/**
 * @brief esp8266获取当前网络时间
 *
 * @return uint8_t  1 返回失败  0 返回成功
 */
uint8_t esp8266_get_time(void)
{
    if (!esp8266_send_cmd("AT+CIPSEND=115", "OK", 60))
    {
        u1_printf("GET http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json&HTTP/1.1\r\n"); // 连接时间的网站
        for (size_t i = 0; i < 0XFFFFF; i++)
        {
            /* code */
        }

        printf("发送信息成功\r\n");
        return 0;
    }
    else
    {
        printf("发送信息失败\r\n");
        return 1;
    }
}

/**
 * @brief esp8266主动断开和TCP服务器的连接
 *
 * @return uint8_t
 */
uint8_t esp8266_disconnect_server(void)
{
    uint8_t isSuccessFlag = esp8266_send_cmd("AT+CIPCLOSE", "OK", 50);
    if (isSuccessFlag == 0)
    {
        printf("esp8266主动断开连接\r\n");
    }
    else
        printf("当前没有服务器连接\r\n");
    return isSuccessFlag;
}

/**
 * @brief esp8266进入透传模式
 *
 * @return uint8_t  成功返回0   失败返回1
 */
uint8_t esp8266_enter_passthrough_mode(void)
{
    if (esp8266_send_cmd("AT+CIPSEND", ">", 50))
    {
        printf("进入透传模式失败\r\n");
        passthrough_mode = 0; // 进入透传模式失败
        return 1;
    }
    else
    {
        printf("进入透传模式成功\r\n");
        passthrough_mode = 1; // 进入透传模式成功
        return 0;
    }
}

/**
 * @brief esp8266退出透传模式
 *
 * @return uint8_t
 */
uint8_t esp8266_exit_passthrough_mode(void)
{
    u1_printf("+++"); // 不发送换行
    for (size_t i = 0; i < 0XFFFF; i++)
    {
    }
    // 等待响应成功
}

/**
 * @brief Get the now time object 获取实时时间, 注意这个函数不能随意调用
 *
 * @return uint8_t  返回0表示成功  返回1表示失败
 */
uint8_t esp8266_get_now_time(void)
{
    for (size_t i = 0; i < 0XFFFF; i++)
    {
        /* code */
    }    // 软件延时，避免繁忙造成连接失败

    esp8266_disconnect_server(); // 断开与服务器的连接
    for (size_t i = 0; i < 0XFFFF; i++)
    {
        /* code */
    }
    // 软件延时，避免繁忙造成连接失败

    while (esp8266_connect_ntim())
        ; // 连接时间网站
    for (size_t i = 0; i < 0XFFFF; i++)
    {
        /* code */
    }
    while (esp8266_get_time()) // 等待成功获取时间
    {
    }

    // if (esp8266_get_time() == 0) // 获取时间
    // {
    //     OS_ERR err;
    //     // OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, NULL, &err); // 等待接收信号量
    //     return 0;
    // }
    return 0;
}

/**
 * @brief 获取时间后必须调用，否则结构里的时间没有更新,注意这个函数只能在任务里面调用，在中断不能调用
 *
 */
void str_to_info(void)
{
    OS_ERR err;
    OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, NULL, &err);
    char time1[30];
    str_get_info(message_buf, get_timeBuf, mystr_type, time1); // 字符串转化为实际值
    transfer_time(time1, &now_time); // 转化为实时时间
    HAL_TIM_Base_Start_IT(&htim2);   // 使能定时器2更新中断
}

/**
 * @brief esp8266 初始化
 *
 */
void esp8266_init(void)
{
    // if (esp8266_send_cmd("AT", "OK", 50)) // AT
    // {
    //     printf("未检测到esp8266, 请重新连接模块\r\n");
    // }
    // else
    // {
    //     printf("已检测到esp8266\r\n");
    // }
    if (esp8266_send_cmd("AT", "OK", 50))
    {
        printf("esp8266连接不正确, 请确认是否连接正确\r\n");
    }

    printf("正在重启模块.....\r\n");
    esp8266_Rst(); // 重启模块
    printf("重启模块成功\r\n");

    if (esp8266_set_mode(3)) // 选择模式3
    {
        printf("esp8266配置失败\r\n");
    }
    else
        printf("已开启AP和STA模式\r\n");

    printf("正在连接手机热点\r\n");
    if (esp8266_connect_wifi(SSID, PASS)) // 连接手机热点
    {
        printf("连接失败, 请检查是否开启手机热点或检查ID和密码\r\n");
    }
    else
    {
        printf("连接手机热点%s成功\r\n", SSID);
    }

    //    printf("正在配置esp8266的AP参数...\r\n");
    //    if(esp8266_set_wifi(WIFINAME, PWD, CHANNEL, ECN))
    //    {
    //        printf("配置失败, 请检查esp8266的连接情况\r\n");
    //    }
    //    else
    //    {
    //        printf("配置成功\r\n");
    //    }
    for (size_t i = 0; i < 0XFFFF; i++)
    {
        /* code */
    }
    ////  OS_ERR err;
    // while (esp8266_get_now_time()) // 等待成功获取
    //    ;

    // esp8266_connect_ntim();
    // esp8266_get_time();
    //  OSTaskSemPend(0, OS_OPT_PEND_BLOCKING, NULL, &err);

    for (size_t i = 0; i < 0XFFFF; i++)
    {
        /* code */
    }

    // esp8266_disconnect_server(); // 断开与服务器的连接
    for (size_t i = 0; i < 0XFFFF; i++)
    {
        /* code */
    }
    // esp8266_disconnect_server();

    // printf("正在连接服务器\r\n");

    while (esp8266_connect_server(IPBUF, PORTNUM))
        ;
    init_success_flag = 1;
    // if (esp8266_connect_server(IPBUF, PORTNUM))
    //{
    //  printf("连接失败,请检查连接的是否为同一个地址\r\n");
    // }
    // else
    //{
    printf("服务器连接成功\r\n");
    // transmit_mode = 1; // 发送信息给服务器
    // HAL_TIM_Base_Start_IT(&htim3); // 开启定时器3更新中断，1s进入一次中断

    //}

    printf("esp8266初始化成功\r\n");
    //}
}

// /**
//  * @brief wifi发送消息给服务器
//  *
//  * @param name 设备名字，如果没有名字，默认为UNCONNECT
//  * @param current 电流
//  * @param voltage 电压
//  * @param power 功率
//  * @param data  时间数据 2020-7-16 00:00:16
//  * @param index_num 串口号 1 2 3
//  * @param power_factor 功率系数
//  * @param frequency 频率 一般为50
//  * @param cumulative_power 累计用电量
//  * @param status   状态位  表示该排插是否使用
//  * @return uint8_t
//  */
// uint8_t esp8266_send_info(char *name, double current, double voltage, double power, char *data, int index_num,
//                           double power_factor, int frequency, double cumulative_power, int status)
// {
//     // char send_buf[] = "\{\"name\":\"%s\"\,\"current\":%.2lf\,\"voltage\":%.2lf\,\"power\":%.2lf\,\"data\":\"%s\"\,\"index_num\":%d\,\"power_factor\":%.2lf\,\"frequency\":50\,\"cumulative_power\":%.2lf\,\"status\":%d\}";
//     //  char send_buf[200];
//     char send_buf[300] = {0};
//     sprintf(send_buf, "{\"name\":\"%s\"\,\"current\":%.5lf\,\"voltage\":%.5lf\,\"power\":%.5lf\,\"data\":\"%s\"\,\"index_num\":%d\,\"power_factor\":%.5lf\,\"frequency\":%d\,\"cumulative_power\":%.5lf\,\"status\":%d}", name, current, voltage, power, data, index_num, power_factor, frequency, cumulative_power, status);
//     printf(send_buf);
//     esp8266_send_server(send_buf); // 发送数据给服务器
//     return 0;
// }

/**
 * @brief 发送信息给服务器, 注意调用时，不能连续发送，应该隔一段时间再发送，否则会出现不稳定的状况
 *
 * @param elc 用电器信息
 * @return uint8_t  成功返回0 失败返回1
 */
uint8_t esp8266_send_info(Elc_Info elc)
{
    // char send_buf[] = "\{\"name\":\"%s\"\,\"current\":%.2lf\,\"voltage\":%.2lf\,\"power\":%.2lf\,\"data\":\"%s\"\,\"index_num\":%d\,\"power_factor\":%.2lf\,\"frequency\":50\,\"cumulative_power\":%.2lf\,\"status\":%d\}";
    //  char send_buf[200];
    char send_buf[300] = {0};
    // 发送特定字符串给服务器
    sprintf(send_buf, "{\"option\":2\,\"name\":\"%s\"\,\"current\":%.5lf\,\"voltage\":%.5lf\,\"power\":%.5lf\,\"date\":\"%s\"\,\"index_num\":%d\,\"power_factor\":%.5lf\,\"frequency\":%.5lf\,\"cumulative_power\":%.5lf\,\"status\":%d}", elc.name, elc.current, elc.voltage, elc.power, elc.time_date, elc.index_num, elc.power_factor, elc.frequency, elc.cumulative_power, elc.status);
    printf(send_buf);
    esp8266_send_server(send_buf); // 发送数据给服务器
    return 0;
}

/**
 * @brief 在指定字符串获取信息, double类型的暂时别用
 *
 * @param source_buf  原来的字符串
 * @param target      目标过滤的字符串
 * @param temp        类别 分为 int double str
 * @param get_buf     将获取到的消息放到缓冲区
 * @return uint8_t    成功返回0  失败返回1
 */
uint8_t str_get_info(const char *source_buf, const char *target, int temp_type, char *get_buf)
{
    char *temp = malloc(300); // 申请空间  存放找到的位置的缓冲区
    uint8_t len = strlen(target);

    temp = strstr(source_buf, target); // 找到对应的位置
    temp += len;                       // 越过该位置
    switch (temp_type)
    {
    case myint_type:
        sscanf(temp, "%d", get_buf);
        break;
    case mydouble_type:
        sscanf(temp, "%lf", get_buf);
        break;
    case mystr_type:
        sscanf(temp, "%[^\"]", get_buf);
        break;
    }
    free(temp); // 释放空间
    return 0;
}

/**
 * @brief 将字符串时间转化为结构体时间
 *
 * @param time_str  字符串时间
 * @param time_struct  实时时间
 * @return uint8_t 成功返回0， 失败返回1
 */
uint8_t transfer_time(char *time_str, Tim_Info *time_struct)
{
    sscanf(time_str, "%d-%d-%d %d:%d:%d", &(time_struct->year), &(time_struct->month), &(time_struct->day), &(time_struct->hour), &(time_struct->minute), &(time_struct->second));
    printf("当前时间为%d-%d-%d %d:%d:%d", time_struct->year, time_struct->month, time_struct->day, time_struct->hour, time_struct->minute, time_struct->second);
    for (size_t i = 0; i < 0XFFFFF; i++)
    {
        /* code */
    }
    printf("%d", time_struct->year);
    return 0;
}

/**
 * @brief esp8266发送报警信息给服务器
 *
 * @return uint8_t 返回0表示成功  返回1表示失败
 */
uint8_t esp8266_send_alarm(void)
{
    char send_buf[300] = {0};
    sprintf(send_buf, "{\"option\":2}"); // 发送特定的字符串给服务端
    printf(send_buf);
    esp8266_send_server(send_buf); // 发送数据给服务器
    return 0;
}
